﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace LetsDeal.Data
{
    public class GenericRepository : IGenericRepository, IDisposable
    {
        public LetsDealDbContext db;

        public GenericRepository(LetsDealDbContext db, bool lazyLoadingEnabled = false, bool proxyCreationEnabled = false)
        {
            this.db = db;
            db.Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
            db.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
        }

        public IEnumerable<TEntity> Get<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, 
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, 
            string includeProperties = "") where TEntity : class
        {
            IQueryable<TEntity> query = db.Set<TEntity>();

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            return query.ToList();
        }

        public TEntity GetById<TEntity>(object id) where TEntity : class
        {
            return db.Set<TEntity>().Find(id);
        }

        public IEnumerable<TEntity> GetAll<TEntity>() where TEntity : class
        {
            return db.Set<TEntity>().AsEnumerable();
        }

        public void Update<TEntity>(TEntity entity) where TEntity : class
        {
            if (db.Entry(entity).State == EntityState.Detached)
            {
                db.Set<TEntity>().Attach(entity);
            }
            db.Entry(entity).State = EntityState.Modified;
        }

        public void Create<TEntity>(TEntity entity) where TEntity : class
        {
            db.Set<TEntity>().Add(entity);
        }

        public void Delete<TEntity>(TEntity entity) where TEntity : class
        {
            if (db.Entry(entity).State == EntityState.Detached)
            {
                db.Set<TEntity>().Attach(entity);
            }
            db.Set<TEntity>().Remove(entity);
        }

        public int SaveChanged(int userId, int companyId)
        {
            return db.SaveChanges(userId, companyId);
        }

        public int SaveChanged()
        {
            return db.SaveChanges();
        }

        public void OpenConnection()
        {
            db.Database.Connection.Open();
        }

        public void CloseConnection()
        {
            db.Database.Connection.Close();
        }

        public IEnumerable<TEntity> ExecuteSqlQuery<TEntity>(string sql, params object[] param) where TEntity : class
        {
            return db.Database.SqlQuery<TEntity>(sql, param).AsEnumerable();
        }

        public int ExecuteSqlCommand(string sql, params object[] param)
        {
            return db.Database.ExecuteSqlCommand(sql, param);
        }

        public IEnumerable<TEntity> ExcuteStore<TEntity>(string name, params object[] param) where TEntity : class
        {
            string sql = "exec " + name;
            if (param != null && param.Length > 0)
            {
                for (int i = 0; i < param.Length; i++)
                {
                    if (i != 0)
                    {
                        sql = sql + ", {" + i + "}";
                    }
                    else
                    {
                        sql = sql + " {" + i + "}";
                    }
                }
                return db.Database.SqlQuery<TEntity>(sql, param).ToList();
            }
            else
            {
                return db.Database.SqlQuery<TEntity>(sql).ToList();
            }
        }

        public void Dispose()
        {
            if (db != null)
            {
                db.Dispose();
                db = null;
            }
        }
    }
}
